package db

import (
	"context"
	"fmt"
	"gitee.com/zy_blue7/db-convert-api/internal/svc"
	"gitee.com/zy_blue7/db-convert-api/internal/types"
	"gitee.com/zy_blue7/db-convert-api/utils"
	db_utils "gitee.com/zy_blue7/db-convert/db-utils"
	"gitee.com/zy_blue7/db-convert/db-utils/mysql"
	"github.com/jinzhu/copier"
	"github.com/zeromicro/go-zero/core/fx"
	"strings"

	"github.com/zeromicro/go-zero/core/logx"
)

type ListLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ListLogic {
	return &ListLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *ListLogic) List(req *types.DataConView) (resp *types.DBViewResp, err error) {
	key := fmt.Sprintf("%s#%s#%s#%s", req.Host, req.Port, req.DriverName, req.Schema)
	dataConvert, ok := l.svcCtx.DataConMap[key]
	if !ok {
		dataConvert = mysql.NewMysql(
			mysql.WithPort(req.Port),
			mysql.WithSchema(req.Schema),
			mysql.WithHost(req.Host),
			mysql.WithPassword(req.Password),
			mysql.WithUserName(req.UserName),
			mysql.WithDriverName(req.DriverName),
		)
		l.svcCtx.DataConMap[key] = dataConvert
	}
	databases, err := dataConvert.GetDatabases()
	ignoreArr := []string{strings.ToLower("information_schema"),
		strings.ToLower("mysql"),
		strings.ToLower("performance_schema"),
		strings.ToLower("sys"),
	}
	var dbView types.DBView

	var dataBaseViews []types.DataBaseView

	dbView.DataConView = *req
	for _, database := range databases {
		if utils.IsContain(ignoreArr, database) {
			continue
		}
		// 表信息/字段信息
		tableColumns, err := dataConvert.GetAllTableColumns(database)
		if err != nil {
			logx.Error(err)
		}
		var dataBaseView types.DataBaseView
		dataBaseView.DatabaseName = database
		var tables []types.TableView
		var primaryKeyTableMap = make(map[string][]types.PrimaryKeyInfo)
		var foreignKeyInfoTableMap = make(map[string][]types.ForeignKeyInfo)
		var indexInfoTableMap = make(map[string][]types.IndexInfo)
		fx.From(func(source chan<- any) {
			for _, column := range tableColumns {
				source <- column
			}
		}).Group(func(item any) any {
			info := item.(db_utils.ColumnInfo)
			return info.TableName
		}).ForEach(func(item any) {
			//fmt.Println(item)
			var table types.TableView

			var columns []types.ColumnInfo

			items := item.([]interface{})
			table.TableName = items[0].(db_utils.ColumnInfo).TableName
			for _, v := range items {
				info := v.(db_utils.ColumnInfo)
				var column types.ColumnInfo
				copier.Copy(&column, &info)

				columns = append(columns, column)
			}
			table.ColumnInfos = append(table.ColumnInfos, columns...)
			tables = append(tables, table)
		})

		// 主键信息
		primaryKeys, err := dataConvert.GetAllPrimaryKeys(database)
		if err != nil {
			logx.Error(err)
		}
		fx.From(func(source chan<- any) {
			for _, primaryKey := range primaryKeys {
				source <- primaryKey
			}
		}).Group(func(item any) any {
			info := item.(db_utils.PrimaryKeyInfo)
			return info.TableName
		}).ForEach(func(item any) {
			items := item.([]interface{})
			tableName := items[0].(db_utils.PrimaryKeyInfo).TableName
			var primaryKeyInfos []types.PrimaryKeyInfo
			for _, info := range items {
				var primaryKeyInfo types.PrimaryKeyInfo
				keyInfo := info.(db_utils.PrimaryKeyInfo)
				copier.Copy(&primaryKeyInfo, keyInfo)
				primaryKeyInfos = append(primaryKeyInfos, primaryKeyInfo)
			}
			primaryKeyTableMap[tableName] = primaryKeyInfos
		})

		// 外建信息
		foreignKeys, err := dataConvert.GetAllForeignKeys(database)
		if err != nil {
			logx.Error(err)
		}
		fx.From(func(source chan<- any) {
			for _, foreignKey := range foreignKeys {
				source <- foreignKey
			}
		}).Group(func(item any) any {
			info := item.(db_utils.ForeignKeyInfo)
			return info.TableName
		}).ForEach(func(item any) {
			items := item.([]interface{})
			tableName := items[0].(db_utils.ForeignKeyInfo).TableName
			var foreignKeyInfos []types.ForeignKeyInfo
			for _, info := range items {
				var foreignKeyInfo types.ForeignKeyInfo
				keyInfo := info.(db_utils.ForeignKeyInfo)
				copier.Copy(&foreignKeyInfo, keyInfo)
				foreignKeyInfos = append(foreignKeyInfos, foreignKeyInfo)
			}
			foreignKeyInfoTableMap[tableName] = foreignKeyInfos
		})

		// 索引信息
		indexes, err := dataConvert.GetAllIndexes(database)
		if err != nil {
			logx.Error(err)
		}
		fx.From(func(source chan<- any) {
			for _, index := range indexes {
				source <- index
			}
		}).Group(func(item any) any {
			info := item.(db_utils.IndexInfo)
			return info.TableName
		}).ForEach(func(item any) {
			items := item.([]interface{})
			tableName := items[0].(db_utils.IndexInfo).TableName
			var indexInfos []types.IndexInfo
			for _, info := range items {
				var indexInfo types.IndexInfo
				keyInfo := info.(db_utils.IndexInfo)
				copier.Copy(&indexInfo, keyInfo)
				indexInfos = append(indexInfos, indexInfo)
			}
			indexInfoTableMap[tableName] = indexInfos
		})

		for i, _ := range tables {
			infos, ok := primaryKeyTableMap[tables[i].TableName]
			if ok {
				tables[i].PrimaryKeyInfos = append(tables[i].PrimaryKeyInfos, infos...)
			}
			foreignKeyInfos, ok := foreignKeyInfoTableMap[tables[i].TableName]
			if ok {
				tables[i].ForeignKeyInfos = append(tables[i].ForeignKeyInfos, foreignKeyInfos...)
			}
			indexInfos, ok := indexInfoTableMap[tables[i].TableName]
			if ok {
				tables[i].IndexInfos = append(tables[i].IndexInfos, indexInfos...)
			}
		}
		dataBaseView.TableViews = append(dataBaseView.TableViews, tables...)
		dataBaseViews = append(dataBaseViews, dataBaseView)
	}

	dbView.DataBaseViews = append(dbView.DataBaseViews, dataBaseViews...)
	return &types.DBViewResp{
		Result: types.Result{
			Code:      200,
			Message:   "",
			ExtInfo:   "",
			Timestamp: 0,
		},
		DBView: dbView,
	}, err
}
